package com.sky.service.common.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.BaseServiceConstant;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.exception.ParameterInvalidException;
import com.sky.exception.ParameterIsNullException;
import com.sky.mapper.admin.SetmealDishMapper;
import com.sky.mapper.admin.SetmealMapper;
import com.sky.pojo.Setmeal;
import com.sky.pojo.SetmealDish;
import com.sky.result.PageResult;
import com.sky.service.common.SetmealService;
import com.sky.vo.DishItemVO;
import com.sky.vo.SetmealVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * 套餐业务实现
 *
 * @author zgp
 * @version V1.0
 * @date 2025-01-15 9:50
 */
@Service
public class SetmealServiceImpl implements SetmealService {
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;

    @Override
    public PageResult<SetmealVO> getPageList(SetmealPageQueryDTO pageQueryDTO) {
        int page = pageQueryDTO.getPage();
        int pageSize = pageQueryDTO.getPageSize();
        // 参数校验
        if (page < BaseServiceConstant.ZERO || pageSize < BaseServiceConstant.ZERO) {
            throw new ParameterInvalidException(MessageConstant.PAGE_PARAMETER_IS_INVALID);
        }
        Integer status = pageQueryDTO.getStatus();
        if (Objects.nonNull(status) && !StatusConstant.ENABLE.equals(status) && !StatusConstant.DISABLE.equals(status)) {
            throw new ParameterInvalidException(MessageConstant.SETMEAL_STATUS_IS_INVALID);
        }
        // 封装查询参数实体
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(pageQueryDTO, setmeal);
        // 分页查询
        PageHelper.startPage(page, pageSize);
        Page<SetmealVO> setmealPage = setmealMapper.selectPageList(setmeal);
        return new PageResult<>(setmealPage.getTotal(), setmealPage.getResult());
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    @CacheEvict(cacheNames = RedisConstant.INDEX_SETMEAL_CACHE_PREFIX, key = "#setmealDTO.categoryId")
    public void addSetmeal(SetmealDTO setmealDTO) {
        // 参数校验
        if (Objects.isNull(setmealDTO.getCategoryId())
                || StringUtils.isEmpty(setmealDTO.getName())
                || Objects.isNull(setmealDTO.getPrice())
                || StringUtils.isEmpty(setmealDTO.getImage())
                || CollUtil.isEmpty(setmealDTO.getSetmealDishes())
                || Objects.isNull(setmealDTO.getStatus())
                || Objects.isNull(setmealDTO.getMakeTime())
        ) {
            throw new ParameterInvalidException(MessageConstant.PARAMES_IS_INVALID);
        }
        if (!StatusConstant.ENABLE.equals(setmealDTO.getStatus()) && !StatusConstant.DISABLE.equals(setmealDTO.getStatus())) {
            throw new ParameterInvalidException(MessageConstant.SETMEAL_STATUS_IS_INVALID);
        }
        // 校验菜品名称是否存在
        int count = setmealMapper.selectByName(setmealDTO.getName());
        if(count > 0){
            throw new ParameterInvalidException(MessageConstant.SETMEAL_NAME_IS_EXIST);
        }
        // 插入套餐基本信息
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(setmealDTO, setmeal);
        // 新增套餐默认停售
        setmeal.setStatus(StatusConstant.DISABLE);
        setmealMapper.insert(setmeal);
        // 新增套餐对应菜品信息
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        setmealDishes.forEach(o -> o.setSetmealId(setmeal.getId()));
        setmealDishMapper.insertOfBatch(setmealDishes);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    @CacheEvict(cacheNames = RedisConstant.INDEX_SETMEAL_CACHE_PREFIX, allEntries = true)
    public void deleteOfBatch(List<Long> ids) {
        // 参数校验
        if(CollUtil.isEmpty(ids)){
            throw new ParameterInvalidException(MessageConstant.ID_IS_NULL);
        }
        // 启售套餐不能删除
        int count = setmealMapper.countStatusAndIds(StatusConstant.ENABLE, ids);
        if(count > 0){
            throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
        }
        // 删除套餐基础信息
        setmealMapper.deleteByIds(ids);
        // 批量删除套餐对应菜品信息
        setmealDishMapper.deleteBySetmealIds(ids);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    @CacheEvict(cacheNames = RedisConstant.INDEX_SETMEAL_CACHE_PREFIX, allEntries = true)
    public void updateById(SetmealDTO setmealDTO) {
        // 参数校验
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        if ( Objects.isNull(setmealDTO.getId())
                || Objects.isNull(setmealDTO.getCategoryId())
                || StringUtils.isEmpty(setmealDTO.getName())
                || Objects.isNull(setmealDTO.getPrice())
                || StringUtils.isEmpty(setmealDTO.getImage())
                || CollUtil.isEmpty(setmealDishes)
                || Objects.isNull(setmealDTO.getStatus())
                || Objects.isNull(setmealDTO.getMakeTime())
        ) {
            throw new ParameterInvalidException(MessageConstant.PARAMES_IS_INVALID);
        }
        if (!StatusConstant.ENABLE.equals(setmealDTO.getStatus()) && !StatusConstant.DISABLE.equals(setmealDTO.getStatus())) {
            throw new ParameterInvalidException(MessageConstant.SETMEAL_STATUS_IS_INVALID);
        }
        // 套餐名称唯一性校验
        SetmealVO setmealVO= setmealMapper.selectById(setmealDTO.getId());
        if(Objects.isNull(setmealVO)){
            throw new ParameterInvalidException(MessageConstant.SETMEAL_NOT_EXIST);
        }
        if(!setmealVO.getName().equals(setmealDTO.getName())){
            // 已修改套餐名称，比较是否和其它套餐重名
            int count = setmealMapper.selectByName(setmealDTO.getName());
            if(count > 0){
                throw new ParameterInvalidException(MessageConstant.SETMEAL_NAME_IS_EXIST);
            }
        }
        // 数据转换
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(setmealDTO, setmeal);
        // 更新套餐基本信息
        setmealMapper.updateById(setmeal);
        // 删除套餐对应的菜品信息
        setmealDishMapper.deleteBySetmealIds(List.of(setmeal.getId()));
        // 新增套餐对应的菜品信息
        setmealDishes.forEach(o -> o.setSetmealId(setmeal.getId()));
        setmealDishMapper.insertOfBatch(setmealDishes);
    }

    @Override
    public SetmealVO getSetmealById(Long id) {
        if(Objects.isNull(id)){
            throw new ParameterIsNullException(MessageConstant.ID_IS_NULL);
        }
        return setmealMapper.selectById(id);
    }

    @Override
    // 删除cacheNames匹配到的所有缓存数据
    @CacheEvict(cacheNames = RedisConstant.INDEX_SETMEAL_CACHE_PREFIX, allEntries = true)
    public void enableOrDisableSetmeal(Integer status, Long id) {
        // 参数校验
        if(Objects.isNull(status) || Objects.isNull(id)){
            throw new ParameterIsNullException(MessageConstant.PARAMES_IS_INVALID);
        }
        if(!StatusConstant.ENABLE.equals(status) && !StatusConstant.DISABLE.equals(status)){
            throw new ParameterInvalidException(MessageConstant.SETMEAL_STATUS_IS_INVALID);
        }
        // 查询套餐中停售菜品数量（启售套餐内不能包含停售菜品）
        int count = setmealMapper.countByDishStatusAndId(StatusConstant.DISABLE, id);
        if(StatusConstant.ENABLE.equals(status) && count > 0){
            throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ENABLE_FAILED);
        }
        // 封装数据
        Setmeal setmeal = new Setmeal();
        setmeal.setId(id);
        setmeal.setStatus(status);
        // 修改套餐
        setmealMapper.updateById(setmeal);
    }

    @Override
    // 该注解标识方法执行前先查询缓存中是否有数据， 有数据直接返回缓存数据；
    // 没有缓存数据，调用方法并将方法返回值放到缓存中
    @Cacheable(cacheNames = RedisConstant.INDEX_SETMEAL_CACHE_PREFIX, key = "#categoryId")
    public List<SetmealVO> getSetmealByCategoryIdAndStatus(Integer categoryId, Integer status) {
        // 参数校验
        if(Objects.isNull(status) || Objects.isNull(categoryId)){
            throw new ParameterIsNullException(MessageConstant.PARAMES_IS_INVALID);
        }
        if(!StatusConstant.ENABLE.equals(status) && !StatusConstant.DISABLE.equals(status)){
            throw new ParameterInvalidException(MessageConstant.SETMEAL_STATUS_IS_INVALID);
        }
        return setmealMapper.selectByCategoryIdAndStatus(categoryId, status);
    }

    @Override
    public List<DishItemVO> getSetmealIncudeDishsById(Long id) {
        // 参数校验
        if(Objects.isNull(id)){
            throw new ParameterIsNullException(MessageConstant.PARAMES_IS_INVALID);
        }
        return setmealDishMapper.selectDishItemBySetmealId(id);
    }
}
